package cn.tom.config;

import cn.tom.dao.RoleDao;
import cn.tom.dao.UserDao;
import cn.tom.entity.Role;
import cn.tom.entity.XUser;
import cn.tom.tools.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 酒辞
 */
@Slf4j
public class JwtAuthoriztionFiler extends BasicAuthenticationFilter {
    private  AuthenticationManager authenticationManager;
    private  RedisTemplate redisTemplate;
    private  UserDao userDao;
    private  RoleDao roleDao;

    public JwtAuthoriztionFiler(AuthenticationManager authenticationManager,
                                RedisTemplate redisTemplate,
                                UserDao userDao,
                                RoleDao roleDao) {
        super(authenticationManager);
        this.redisTemplate = redisTemplate;
        this.userDao = userDao;
        this.roleDao = roleDao;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        log.info("获取请求头中 Token");
        String bearer = request.getHeader("Authorization");
        log.info("Bearer="+bearer);
        //Bearer eyJOeXAii KV1QilC hbGci0iJIUzINi J9.eyJyb2xlcyI6Im
        if (bearer == null || bearer.length()<7){//没有带 Token，permitAll()
            log.info("直接放开的，无需Token 就可以访问");
            chain.doFilter(request,response);//调用下一个过滤器
            return;
        }
        String token=bearer.substring(7);


        String redisToken = (String)
                redisTemplate.opsForValue()
                        .get("token:"+ token);
        if( !(redisToken.equals(token) ) ){
            //不是自己颁发的token
            log.info("Token不一致");
            response.setStatus(403);
            // 拒绝访问
            response.getWriter().println("Token不一致");
            return;
        }

        log.info("Token="+token);
        //验证 token
        if (JwtUtil.isValid(token)==false){
            log.info("Token 被人篡改或过期，拒绝访问");
            response.setStatus(403);
            // 拒绝访问
            response.getWriter().println("Token 被篡改或过期");
            return;
        }
        //token 合格，让 SpringSecurity 去判断角色能干什么
        log.info("token 合格，让 SpringSecurity 去判断角色能干什么");

        Integer uid = JwtUtil.getUid(token);
        if (uid == null ){
            response.setStatus(403);
            // 拒绝访问
            response.getWriter().println("Token信息不一致");
            return;
        }
        XUser user = getUserInfo(uid);
        System.out.println("token"+user.getId());
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(uid,null,user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        chain.doFilter(request,response);
    }
    private XUser getUserInfo(Integer uid){
        XUser user =(XUser) redisTemplate.opsForHash().get("userInfo", uid);
        if (user == null){
            user = userDao.findById(uid);
            List<String> roles = getUserRole(uid);
            user.setRoles(roles);
            redisTemplate.opsForHash().put("userInfo",uid,user);
        }
        return user;
    }

    private List<String>  getUserRole(Integer uid){
        List<String> roles = (List<String>) redisTemplate.opsForHash().get("userRole",uid);
        if (roles == null){
            roles = new ArrayList<>();
            // 如果没有创建对象
            List<Integer> roleIds = roleDao.findByUidRoles(uid);
            for (Integer roleId : roleIds) {
                Role role =(Role) redisTemplate.opsForHash().get("role", roleId);
                if (role == null){
                    role = roleDao.findByRoleId(roleId);
                    redisTemplate.opsForHash().put("role",role.getId(),role);
                }
                roles.add(role.getRoleName());
                // 储存角色信息
                redisTemplate.opsForHash().put("userRole",uid,roles);
            }
            // 最后将用户角色信息储存进Redis中 方便下次获取
        }
        return roles;
    }
}
